﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Security.Principal;
using System.Reflection;
using Eacademy.Domain.Abstractions;
using Eacademy.Domain.Models;
using Eacademy.Library.Membership;
using Ninject;

namespace Eacademy.Library.Actions
{
    public class AcceptParameterAttribute : ActionMethodSelectorAttribute
    {

        public string Name { get; set; }
        public string Value { get; set; }


        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
        {
            var req = controllerContext.RequestContext.HttpContext.Request;
            return req.Form[this.Name] == this.Value;
        }
    }

    //Partial Validation 
    //http://blog.stevensanderson.com/2010/02/19/partial-validation-in-aspnet-mvc-2/
    //**
    public class ValidateOnlyIncomingValuesAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var modelState = filterContext.Controller.ViewData.ModelState;
            var valueProvider = filterContext.Controller.ValueProvider;

            var keysWithNoIncomingValue = modelState.Keys.Where(x => !valueProvider.ContainsPrefix(x));
            foreach (var key in keysWithNoIncomingValue)
                modelState[key].Errors.Clear();
        }
    }


    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public class CustomAuthorizeAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// The name of the master page or view to use when rendering the view on authorization failure.  Default
        /// is null, indicating to use the master page of the specified view.
        /// </summary>
        public virtual string MasterName { get; set; }

        /// <summary>
        /// The name of the view to render on authorization failure.  Default is "Error".
        /// </summary>
        public virtual string ViewName { get; set; }

        public CustomAuthorizeAttribute()
            : base()
        {
            this.ViewName = "Error";
        }

        /*http://geekswithblogs.net/apopovsky/archive/2009/05/06/working-around-flash-cookie-bug-in-asp.net-mvc.aspx*/
        /// <summary>
        /// The key to the authentication token that should be submitted somewhere in the request.
        /// </summary>
        private const string TOKEN_KEY = "authtoken";

        /// <summary>
        /// This changes the behavior of AuthorizeCore so that it will only authorize
        /// users if a valid token is submitted with the request.
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
        {
            string token = httpContext.Request.Params[TOKEN_KEY];

            if (token != null)
            {
                //token = token.Replace(" ", "+");

                FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(token);

                if (ticket != null)
                {
                    FormsIdentity identity = new FormsIdentity(ticket);
                    //string[] roles = System.Web.Security.Roles.GetRolesForUser(identity.Name);
                    string[] roles = { "admin" };
                    GenericPrincipal principal = new GenericPrincipal(identity, roles);
                    httpContext.User = principal;
                }
            }

            bool ret = base.AuthorizeCore(httpContext);
            return ret;
        }

        /**/

        protected void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
        {
            validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
        }

        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            if (AuthorizeCore(filterContext.HttpContext))
            {
                SetCachePolicy(filterContext);
            }
            else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                // auth failed, redirect to login page
                //filterContext.Result = new HttpUnauthorizedResult();

                // root
                //string loginUrl = "/";
                //filterContext.Result = new RedirectResult(loginUrl);

                var redirectPath = "~/{0}";
                var returnUrl = HttpUtility.UrlEncode(filterContext.HttpContext.Request.RawUrl);
                if (string.IsNullOrEmpty(returnUrl) || returnUrl == "/")
                    redirectPath = string.Format(redirectPath, string.Empty);
                else
                    redirectPath = string.Format(redirectPath, string.Format("?returnurl={0}", returnUrl));

                filterContext.Result = new RedirectResult(redirectPath);
            }
            //else if (filterContext.HttpContext.User.IsInRole("SuperUser"))
            //{
            //    // is authenticated and is in the SuperUser role
            //    SetCachePolicy(filterContext);
            //}
            else
            {
                //ViewDataDictionary viewData = new ViewDataDictionary();
                //viewData.Add("Message", "You do not have sufficient privileges for this operation.");
                //TempDataDictionary tempData = new TempDataDictionary();
                //tempData.Add("Error", "You do not have sufficient privileges for this operation.");
                //filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, TempData = tempData };
                //filterContext.Result = new ContentResult { Content = "hello" };
                filterContext.Controller.TempData["Error"] = "You do not have sufficient privileges for this operation.";
                filterContext.Result = new RedirectResult("/");
            }

        }

        protected void SetCachePolicy(AuthorizationContext filterContext)
        {
            // ** IMPORTANT **
            // Since we're performing authorization at the action level, the authorization code runs
            // after the output caching module. In the worst case this could allow an authorized user
            // to cause the page to be cached, then an unauthorized user would later be served the
            // cached page. We work around this by telling proxies not to cache the sensitive page,
            // then we hook our custom authorization code into the caching mechanism so that we have
            // the final say on whether a page should be served from the cache.
            HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
            cachePolicy.SetProxyMaxAge(new TimeSpan(0));
            cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
        }


    }

    //http://thatstoday.com/article/1965935/anti-forgery-request-helpers-for-aspnet-mvc-and-jquery-ajax
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class ValidateAntiForgeryTokenWrapperAttribute : FilterAttribute, IAuthorizationFilter
    {
        private readonly ValidateAntiForgeryTokenAttribute _validator;

        private readonly AcceptVerbsAttribute _verbs;

        public ValidateAntiForgeryTokenWrapperAttribute(HttpVerbs verbs)
            : this(verbs, null)
        {
        }

        public ValidateAntiForgeryTokenWrapperAttribute(HttpVerbs verbs, string salt)
        {
            this._verbs = new AcceptVerbsAttribute(verbs);
            this._validator = new ValidateAntiForgeryTokenAttribute()
            {
                Salt = salt
            };
        }

        public void OnAuthorization(AuthorizationContext filterContext)
        {
            string httpMethodOverride = filterContext.HttpContext.Request.GetHttpMethodOverride();
            if (this._verbs.Verbs.Contains(httpMethodOverride, StringComparer.OrdinalIgnoreCase))
            {
                this._validator.OnAuthorization(filterContext);
            }
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class ProfileControllerFilter : ActionFilterAttribute
    {

        public int UserType { get; set; }

        private IStudentRepository _studentRepository;

        [Inject]
        public IStudentRepository StudentRepository
        {
            set
            {
                _studentRepository = value;
            }
        }

        private IMentorRepository _mentorRepository;

        [Inject]
        public IMentorRepository MentorRepository
        {
            set
            {
                _mentorRepository = value;
            }
        }


        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            CustomMembershipProvider provider = (CustomMembershipProvider)System.Web.Security.Membership.Provider;

            if (provider.User == null)
            {
                FormsAuthentication.SignOut();
                FormsAuthentication.RedirectToLoginPage();
            }

            filterContext.Controller.ViewData["UserTypeId"] = provider.User.UserTypeId;

            string relaveFilePath;
            switch (provider.User.UserTypeId)
            {
                case UserTypes.Student:
                    AdminStudentsViewModel student = _studentRepository.GetStudentByUserId((int)provider.User.UserId);
                    relaveFilePath = AppSettings.AvatarImageDirectory.Replace("~", "");
                    student.ThumbImagePathName = String.Format("{0}{1}", relaveFilePath, student.ThumbImageName);
                    filterContext.Controller.ViewData["model"] = student;
                    break;
                case UserTypes.Mentor:
                    AdminMentorsViewModel mentor = _mentorRepository.GetMentorByUserId((int)provider.User.UserId);
                    relaveFilePath = AppSettings.AvatarImageDirectory.Replace("~", "");
                    mentor.ThumbImagePathName = String.Format("{0}{1}", relaveFilePath, mentor.ThumbImageName);
                    filterContext.Controller.ViewData["model"] = mentor;
                    break;
            }

        }
    }
}
